﻿/**
 * @file MsgQueue.h
 * @brief message queue
 * $Id: MsgQueue.h 13 2011-01-01 11:48:27Z tonyjobmails $
 * $Date: 2011-01-01 11:48:27 +0000 (Sat, 01 Jan 2011) $
 * $Author: tonyjobmails $
 * $Revision: 13 $
 */
#ifndef __MSG__QUEUE__H
#define __MSG__QUEUE__H

#include <ext/mt_allocator.h>
#include <queue>
#include <deque>
#include <string.h>
#include "Log.h"

typedef std::pair<unsigned int, unsigned char *> MsgPair;

template<unsigned int QUEUE_SIZE = 1024>
class MsgQueue
{
	public:
		/**
		 * @brief 构造
		 */
		MsgQueue() : front(0), tail(0) {};
		
		/**
		 * @brief 析构
		 */
		~MsgQueue()
		{
			this->clear();
		}
		
		/**
		 * @brief 指令入队
		 * @param msg：指令地址
		 * @param len：指令长度
		 */
		bool push(const void *msg, const unsigned int len)
		{
			if(msg && len)
			{
				unsigned char* buff = alloc.allocate(len);
				if(buff)
				{
					bcopy(msg, buff, len);
					if(this->shift2RealQueue() && !this->stcQueue[this->front].first)
					{
						this->stcQueue[this->front].second = std::make_pair(len, buff);
						this->stcQueue[this->front].first = true;
						this->front = ++(this->front) % QUEUE_SIZE;
					}
					else
					{
						this->dynQueue.push(std::make_pair(len, buff));
					}
					
					return true;
				}
			}
			
			return false;
		}
		
		/**
		 * @brief 指令出队
		 */
		MsgPair* pop()
		{
			if(this->stcQueue[this->tail].first)
				return &(this->stcQueue[this->tail].second);
		}
		
		/**
		 * @brief 移除静态队列中的队尾元素
		 */
		void erase()
		{
			if(this->stcQueue[this->tail].first)
			{
				alloc.deallocate(this->stcQueue[this->tail].second.second, this->stcQueue[this->tail].second.first);
				this->stcQueue[this->tail].first = false;
				this->tail = ++(this->tail) % QUEUE_SIZE;
			}
		}
#ifdef _TOTO_DEBUG
		void outputAll()
		{
			log::_DEBUG_LOG("dynQueue size：%u", dynQueue.size());
			if(this->stcQueue[this->tail].first)
			{
				unsigned int pos = this->tail;
				do
				{
					if(this->stcQueue[pos].first && this->stcQueue[pos].second.second)
					{
						std::vector<char> data;
						data.resize(this->stcQueue[pos].second.first + 1);
						bcopy(this->stcQueue[pos].second.second, &data[0], this->stcQueue[pos].second.first);
						data[this->stcQueue[pos].second.first] = '\0';

						log::_DEBUG_LOG("stcQueue %ust：%s", pos + 1, &data[0]);
					}
					++pos;
					pos %= QUEUE_SIZE;
				}
				while(pos != this->front);
			}
			else
			{
				log::_DEBUG_LOG("stcQueue size：0");
			}
		}
#endif
		
	private:
		/**
		 * @brief 清除队列
		 */
		void clear()
		{
			while(!shift2RealQueue())
			{
				erase();
			}
			erase();
		}
		
		/**
		 * @brief 移到动态队列中的元素到静态队列
		 * @return 是否移动完成
		 */
		bool shift2RealQueue()
		{
			bool shiftout = true;
			
			while(!dynQueue.empty())
			{
				if(!stcQueue[this->front].first)
				{
					stcQueue[this->front].second = dynQueue.front();
					stcQueue[this->front].first = true;
					this->front = ++(this->front) % QUEUE_SIZE;
					
					dynQueue.pop();
				}
				else
				{
					shiftout = false;
					break;
				}
			}
			
			return shiftout;
		}
		
	private:
		typedef __gnu_cxx::__mt_alloc<unsigned char> __mt_alloc;
		__mt_alloc alloc;
		
		std::queue<MsgPair, std::deque<MsgPair, __mt_alloc > > dynQueue;	/// 动态队列
		
		std::pair<bool, MsgPair> stcQueue[QUEUE_SIZE];		/// 静态队列
		unsigned int front;			/// 队头指针
		unsigned int tail;			/// 队尾指针
};

#endif	/// __MSG__QUEUE__H

